package org.codehaus.mojo.l10n;

import java.io.File;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;

import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.reporting.AbstractMavenReportRenderer;
import org.codehaus.plexus.util.StringUtils;

/**
 * Generates an overview page with a list of properties bundles and a link to
 * each locale's status.
 */
class L10NStatusRenderer extends AbstractMavenReportRenderer {

	/**
	 * 
	 */
	private final L10NStatusReport l10nStatusReport;

	private final ResourceBundle bundle;

	/**
	 * The locale in which the report will be rendered.
	 */
	private final Locale rendererLocale;

	private Set<File> files;

	public L10NStatusRenderer(L10NStatusReport l10nStatusReport, Sink sink,
			ResourceBundle bundle, Locale rendererLocale) {
		super(sink);
		this.l10nStatusReport = l10nStatusReport;

		this.bundle = bundle;
		// this.files = files;
		this.rendererLocale = rendererLocale;
	}

	/**
	 * @see org.apache.maven.reporting.AbstractMavenReportRenderer#renderBody()
	 */
	public void renderBody() {
		String defaultLocaleColumnName = bundle
				.getString("report.l10n.column.default");
		String missingFileLabel = bundle.getString("report.l10n.missingFile");
		String missingKeysLabel = bundle.getString("report.l10n.missingKey");
		String okLabel = bundle.getString("report.l10n.ok");
		String totalLabel = bundle.getString("report.l10n.total");
		String additionalKeysLabel = bundle.getString("report.l10n.additional");
		String nontranslatedKeysLabel = bundle
				.getString("report.l10n.nontranslated");

		// top section
		startSection(getTitle());
		paragraph(bundle.getString("report.l10n.intro"));
		// summary table
		renderSummaryTable();

		// add totals to summary table
		// int[] count = new int[locales != null ? locales.size() + 1 : 1];
		// Arrays.fill(count, 0);
		// Iterator<Wrapper> fileIterator = files.iterator();
		// MavenProject lastPrj = null;
		// Set<Wrapper> usedFiles = new TreeSet<Wrapper>( new
		// WrapperComparator() );
		// while ( fileIterator.hasNext() )
		// {
		// Wrapper wr = (Wrapper) fileIterator.next();
		// if ( this.l10nStatusReport.reactorProjects.size() > 1 && ( lastPrj ==
		// null || lastPrj != wr.getProject() ) )
		// {
		// lastPrj = wr.getProject();
		// sink.tableRow();
		// String name = wr.getProject().getName();
		// if ( name == null )
		// {
		// name = wr.getProject().getGroupId() + ":" +
		// wr.getProject().getArtifactId();
		// }
		// tableCell( "<b><i>" + name + "</b></i>", true );
		// sink.tableRow_();
		// }
		// if (isDefaultLocaleFilename(wr.getFile().getName())) {
		// usedFiles.add( wr );
		// sink.tableRow();
		// tableCell( wr.getPath() );
		// Properties props = new Properties();
		// BufferedInputStream inputStream = null;
		// try
		// {
		// inputStream = new BufferedInputStream( new FileInputStream(
		// wr.getFile() ) );
		// props.load( inputStream );
		// wr.getProperties().put( Wrapper.DEFAULT_LOCALE, props );
		// tableCell( "" + props.size(), true );
		// count[0] = count[0] + props.size();
		// if ( locales != null )
		// {
		// Iterator localeIterator = locales.iterator();
		// int i = 1;
		// while ( localeIterator.hasNext() )
		// {
		// String locale = (String) localeIterator.next();
		// String nm = wr.getFile().getName();
		// String fn = nm.substring( 0, nm.length() - ".properties".length() );
		// File locFile = new File( wr.getFile().getParentFile(), fn + "_" +
		// locale + ".properties" );
		// if ( locFile.exists() )
		// {
		// BufferedInputStream in2 = null;
		// Properties props2 = new Properties();
		// try
		// {
		// in2 = new BufferedInputStream( new FileInputStream( locFile ) );
		// props2.load( in2 );
		// wr.getProperties().put( locale, props2 );
		// Set missing = new HashSet( props.keySet() );
		// missing.removeAll( props2.keySet() );
		// Set additional = new HashSet( props2.keySet() );
		// additional.removeAll( props.keySet() );
		// Set nonTranslated = new HashSet();
		// Iterator propertyKeyIterator = props.keySet().iterator();
		// while ( propertyKeyIterator.hasNext() )
		// {
		// String key = (String) propertyKeyIterator.next();
		// String value1 = props.getProperty( key );
		// String value2 = props2.getProperty( key );
		// if ( value2 != null && value1.equals( value2 ) )
		// {
		// nonTranslated.add( key );
		// }
		// }
		// count[i] = count[i] + ( props.size() - missing.size() -
		// nonTranslated.size() );
		// StringBuffer statusRows = new StringBuffer();
		// if ( missing.size() != 0 )
		// {
		// statusRows.append( "<tr><td>" + missingKeysLabel + "</td><td><b>"
		// + missing.size() + "</b></td></tr>" );
		// }
		// else
		// {
		// statusRows.append( "<tr><td>&nbsp;</td><td>&nbsp;</td></tr>" );
		// }
		// if ( additional.size() != 0 )
		// {
		// statusRows.append( "<tr><td>" + additionalKeysLabel + "</td><td><b>"
		// + additional.size() + "</b></td></tr>" );
		// }
		// else
		// {
		// statusRows.append( "<tr><td>&nbsp;</td><td>&nbsp;</td></tr>" );
		// }
		// if ( nonTranslated.size() != 0 )
		// {
		// statusRows.append( "<tr><td>" + nontranslatedKeysLabel +
		// "</td><td><b>"
		// + nonTranslated.size() + "</b></td></tr>" );
		// }
		// tableCell( wrapInTable( okLabel, statusRows.toString() ), true );
		// }
		// finally
		// {
		// IOUtil.close( in2 );
		// }
		// }
		// else
		// {
		// tableCell( missingFileLabel );
		// count[i] = count[i] + 0;
		// }
		// i = i + 1;
		// }
		// }
		// }
		// catch ( IOException ex )
		// {
		// this.l10nStatusReport.getLog().error( ex );
		// }
		// finally
		// {
		// IOUtil.close( inputStream );
		// }
		// sink.tableRow_();
		// }
		// }
		// sink.tableRow();
		// tableCell( totalLabel );
		// for ( int i = 0; i < count.length; i++ )
		// {
		// if ( i != 0 && count[0] != 0 )
		// {
		// tableCell( "<b>" + count[i] + "</b><br />(" + ( count[i] * 100 /
		// count[0] ) + "&nbsp;%)", true );
		// }
		// else if ( i == 0 )
		// {
		// tableCell( "<b>" + count[i] + "</b>", true );
		// }
		// }
		// sink.tableRow_();
		//
		endTable();
		sink.paragraph();
		text(bundle.getString("report.l10n.legend"));
		sink.paragraph_();
		sink.list();
		sink.listItem();
		text(bundle.getString("report.l10n.list1"));
		sink.listItem_();
		sink.listItem();
		text(bundle.getString("report.l10n.list2"));
		sink.listItem_();
		sink.listItem();
		text(bundle.getString("report.l10n.list3"));
		sink.listItem_();
		sink.list_();
		sink.paragraph();
		text(bundle.getString("report.l10n.note"));
		sink.paragraph_();
		endSection();
		endSection();
		if (this.l10nStatusReport.details
				&& this.l10nStatusReport.getL10ns() != null) {
			renderFileDetails(this.l10nStatusReport.getL10ns());
		}
		l10nStatusReport.getLog().debug("End of report.");
	}

	private void createSummaryTableHeaders(String firstHeader,
			List<String> locales) {
		tableHeaderCell(firstHeader);
		if (locales != null) {
			for (String localeCode : locales) {
				// TODO: localize
				// tableHeaderCell(getLocaleDisplayName(localeCode));
				// tableHeaderCell(getLocaleDisplayName(localeCode));
				sink.tableHeaderCell();
				sink.text(getLocaleDisplayName(localeCode));
				sink.lineBreak();
				sink.text("Keys");
				sink.tableHeaderCell_();
				sink.tableHeaderCell();
				sink.text(getLocaleDisplayName(localeCode));
				sink.lineBreak();
				sink.text("Missing keys");
				sink.tableHeaderCell_();
				sink.tableHeaderCell();
				sink.text(getLocaleDisplayName(localeCode));
				sink.lineBreak();
				sink.text("Readiness");
				sink.tableHeaderCell_();
			}
		}
	}

	private void renderSummaryTable() {
		String pathColumnName = bundle.getString("report.l10n.column.path");
		// TODO set pre-calculated locales as a field
		List<String> locales = l10nStatusReport.getLocaleStrings();
		// summary section
		startSection(bundle.getString("report.l10n.summary"));
		startTable();
		tableCaption(bundle.getString("report.l10n.summary.caption"));
		// calculate headers for summary table
		sink.tableRow();
		createSummaryTableHeaders(pathColumnName, locales);
		sink.tableRow_();
		// add statuses to summary table
		for (L10n l10n : this.l10nStatusReport.getL10ns().values()) {
			sink.tableRow();
			tableCell(l10n.getBasename() + L10n.FILE_EXTENSION);
			for (String locale : locales) {
				L10nFile l10nFile = l10n.getFiles().get(locale);
				if (l10nFile != null) {
					tableCell(Integer.toString(l10nFile.getKeyCount()));
					sink.tableCell();
					if (l10nFile.getMissingKeyCount() > 0) {
						renderWarningIcon();
					}
					text(Integer.toString(l10nFile.getMissingKeyCount()));
					sink.tableCell_();
					int keyCount = l10nFile.getKeyCount();
					float readyness = 0;
					if (keyCount > 0) {
						readyness = (((float) keyCount - l10nFile
								.getMissingKeyCount()) / keyCount) * 100;
					}
					tableCell(String.format("%.0f%%", readyness));
				} else {
					// TODO localize
					tableCell("No file");
					sink.tableCell();
					renderWarningIcon();
					sink.tableCell_();
				}
			}
			sink.tableRow_();
		}
		sink.tableRow();
		// add totals to summary table
		// TODO localize
		tableCell("Total");
		for (int i = 0; i < locales.size(); i++) {
			int[] keyTotals = l10nStatusReport.getKeyTotals();
			tableCell(Integer.toString(keyTotals[i]));
			int[] missingKeyTotals = l10nStatusReport.getMissingKeyTotals();
			tableCell(Integer.toString(missingKeyTotals[i]));
			int keyCount = keyTotals[i];
			float readyness = 0;
			if (keyCount > 0) {
				readyness = (((float) keyCount - missingKeyTotals[i]) / keyCount) * 100;
			}
			tableCell(String.format("%.0f%%", readyness));
		}
		sink.tableRow_();
	}

	public String getLocaleDisplayName(String locale) {
		if (locale == null || locale.length() == 0) {
			return "Default";
		} else {
			return locale;
		}
	}

	private void renderFileDetails(Map<String, L10n> l10ns) {
		// TODO localize
		List<String> locales = l10nStatusReport.getLocaleStrings();
		startSection("Keys");
		if (locales != null && l10ns != null) {
			for (L10n l10n : l10ns.values()) {
				startSection(l10n.getBasename());
				startTable();
				tableHeaderCell("Key");
				// String[] headerStrings = new String[locales.size() + 1];
				// headerStrings[0] = "Key";
				// headerStrings[1] = Wrapper.DEFAULT_LOCALE;
				for (String locale : locales) {
					// for (int i = 1; i < headerStrings.length; i++) {
					// headerStrings[i] = (String) locales.get(i - 1);
					tableHeaderCell(locale);
				}
				// tableHeader(headerStrings);
				for (String key : l10n.getKeys()) {
					sink.tableRow();
					tableCell(key.toString());
					for (String locale : locales) {
						String value = l10n.getProperty(locale, key);
						if (value == null) {
							sink.tableCell();
							renderWarningIcon();
							// "<font color=\"#FF0000\">&lt;no value&gt;</font>",
							sink.text("no value");
							sink.tableCell_();
						} else {
							tableCell(value);
						}
					}
					sink.tableRow_();
				}
				endTable();
				endSection();
			}
		}
		endSection();
	}

	/**
	 * Take the supplied locale code, split into its different parts and create
	 * a Locale object from it.
	 * 
	 * @param localeCode
	 *            The code for a locale in the format
	 *            language[_country[_variant]]
	 * @return A suitable Locale object, ot <code>null</code> if the code was in
	 *         an unknown format
	 */
	private Locale createLocale(String localeCode) {
		if (localeCode == null || localeCode.length() == 0) {
			return Locale.ROOT;
		}
		// Split the localeCode into language/country/variant
		String[] localeComponents = StringUtils.split(localeCode, "_");
		Locale locale = null;
		if (localeComponents.length == 1) {
			locale = new Locale(localeComponents[0]);
		} else if (localeComponents.length == 2) {
			locale = new Locale(localeComponents[0], localeComponents[1]);
		} else if (localeComponents.length == 3) {
			locale = new Locale(localeComponents[0], localeComponents[1],
					localeComponents[2]);
		}
		return locale;
	}

	private String wrapInTable(String cell) {
		if (cell == null || cell.length() == 0) {
			cell = "";
		} else {
			cell = "<table><tbody>" + cell + "</tbody></table>";
		}
		return cell;
	}

	protected void renderWarningIcon() {
		sink.figure();
		sink.figureGraphics("images/icon_warning_sml.gif");
		sink.figure_();
	}

	protected void renderSuccessIcon() {
		sink.figure();
		sink.figureGraphics("images/icon_success_sml.gif");
		sink.figure_();
	}

	/**
	 * @see org.apache.maven.reporting.MavenReportRenderer#getTitle()
	 */
	public String getTitle() {
		return bundle.getString("report.l10n.title");
	}
}